home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / ada_gwu / stat.c < prev    next >
C/C++ Source or Header  |  1996-01-30  |  18KB  |  663 lines

  1. /*
  2.  * Copyright (C) 1985-1992  New York University
  3.  * 
  4.  * This file is part of the Ada/Ed-C system.  See the Ada/Ed README file for
  5.  * warranty (none) and distribution info and also the GNU General Public
  6.  * License for more details.
  7.  
  8.  */
  9.  
  10. #define GEN
  11.  
  12. #include "hdr.h"
  13. #include "vars.h"
  14. #include "gvars.h"
  15. #include "ops.h"
  16. #include "segment.h"
  17. #include "setp.h"
  18. #include "genp.h"
  19. #include "exprp.h"
  20. #include "namp.h"
  21. #include "procp.h"
  22. #include "maincasp.h"
  23. #include "miscp.h"
  24. #include "gmiscp.h"
  25. #include "gutilp.h"
  26. #include "statp.h"
  27.  
  28. static void select_move(Node, Symbol);
  29. static Tuple sort_case(Tuple);
  30. static int tcompar(Tuple *, Tuple *);
  31. void compile_body(Node, Node, Node, int);
  32. static int jump_false_code(Symbol);
  33. static int jump_true_code(Symbol);
  34. static Symbol jump_table_get(Tuple, int);
  35. static Tuple jump_table_put(Tuple, int, Symbol);
  36.  
  37. /* Chapter 5: statements
  38.  * 5.2: Assignment statement
  39.  */
  40.  
  41. void select_assign(Node var_node, Node expr_node, Symbol type_name)
  42.                                                             /*;select_assign*/
  43. {
  44.     Symbol    var_name, expr_name;
  45.  
  46.     var_name = N_UNQ(var_node);
  47.     expr_name = N_UNQ(expr_node);
  48.     if (is_simple_type(type_name) && is_simple_name(var_node)
  49.       && !is_renaming(var_name) ) {
  50.         if ((is_simple_name(expr_node) && N_KIND(expr_node) != as_null
  51.           && !is_renaming(expr_name))
  52.           || (N_KIND(expr_node) == as_selector 
  53.           || N_KIND(expr_node) == as_index 
  54.           || N_KIND(expr_node) == as_all)) {
  55.             gen_address(expr_node);
  56.             gen_ks(I_INDIRECT_POP, kind_of(type_name), var_name);
  57.         }
  58.         else {
  59.             gen_value(expr_node);
  60.             gen_ks(I_POP, kind_of(type_name), var_name);
  61.         }
  62.     }
  63.     else {
  64.         gen_address(var_node);
  65.         select_move(expr_node, type_name);
  66.     }
  67. }
  68.  
  69. static void select_move(Node node, Symbol type_name)        /*;select_move*/
  70. {
  71.  
  72.     if (is_simple_type(type_name)) {
  73.         if ((N_KIND(node) != as_null
  74.           && is_simple_name(node) && !is_renaming(N_UNQ(node)))
  75.           || (N_KIND(node) == as_selector || N_KIND(node) == as_index
  76.           || N_KIND(node) == as_all)) {
  77.             gen_address(node);
  78.             gen_k(I_INDIRECT_MOVE, kind_of(type_name));
  79.         }
  80.         else {
  81.             gen_value(node);
  82.             gen_k(I_MOVE, kind_of(type_name));
  83.         }
  84.     }
  85.     else {
  86.         if (is_array_type(type_name)) {
  87.             gen_value(node);
  88.             gen(I_ARRAY_MOVE);
  89.         }
  90.         else {
  91.             gen_value(node);
  92.             gen_s(I_RECORD_MOVE, type_name);
  93.         }
  94.     }
  95. }
  96.  
  97. /* 5.4: Case statement */
  98. Tuple make_case_table(Node cases_node)                     /*;make_case_table*/
  99. {
  100.     /* Function : takes a set of alternatives, and produces a linear table
  101.      *            suitable for jump table, of case ranges sorted in ascending
  102.      *            order. Some optimisation is done, to merge contiguous
  103.      *            ranges and to fill missing ranges with "others" case
  104.      * Input : case_node       ::= {case_statements}
  105.      *         case_statements ::= [choice_list, body]
  106.      *         choice_list     ::= { choice }
  107.      *         choice          ::= simple_choice | range_choice
  108.      *                                           | others_choice
  109.      *      simple_choice   ::= [ value ]
  110.      *         range_choice    ::= [ subtype ]
  111.      * Output : [table, bodies, others_body]
  112.      *          table ::= [ [ lower_bound, index ] ]
  113.      *            -  an extra pair is added with a "lower_bound" one step
  114.      *               higher than necessary
  115.      *            -  "index" is an index in the tuple "bodies", and
  116.      *               index = 0 means "others"
  117.      */
  118.     Node    case_statements_node, choice_list_node, body_node, choice_node,
  119.         lbd_node, ubd_node, others_body;
  120.     Tuple    result, tup, bodies, triplets;
  121.     int        index, a1, a2, a3, b1, b2, b3, lbd_int, ubd_int;
  122.     int        empty;
  123.     Fortup    ft1, ft2;
  124.  
  125. #ifdef TRACE
  126.     if (debug_flag)
  127.         gen_trace_node("MAKE_CASE_TABLE", cases_node);
  128. #endif
  129.  
  130.     /* 1. build a set of triples [lowerbound, upperbound, index] */
  131.  
  132.     index       = 0;
  133.     bodies      = tup_new(0);
  134.     triplets    = tup_new(0);
  135.     others_body = OPT_NODE;
  136.     FORTUP(case_statements_node = (Node), N_LIST(cases_node), ft1);
  137.         choice_list_node = N_AST1(case_statements_node);
  138.         body_node = N_AST2(case_statements_node);
  139.         index += 1;
  140.         empty  = TRUE;  /* may be we have an empty branch */
  141.         FORTUP(choice_node = (Node), N_LIST(choice_list_node), ft2);
  142.             switch (N_KIND(choice_node)) {
  143.             case (as_range):
  144.                 lbd_node = N_AST1(choice_node);
  145.                 ubd_node = N_AST2(choice_node);
  146.                 lbd_int = get_ivalue_int(lbd_node);
  147.                 ubd_int = get_ivalue_int(ubd_node);
  148.                 if (lbd_int <= ubd_int) {
  149.                     tup = tup_new(3);
  150.                     tup[1] = (char *) lbd_int;
  151.                     tup[2] = (char *) ubd_int;
  152.                     tup[3] = (char *) index;
  153.                     triplets = tup_with(triplets, (char *) tup);
  154.                     empty = FALSE;
  155.                 }
  156.                 break;
  157.  
  158.             case (as_others_choice):
  159.                 others_body = body_node;
  160.                 break;
  161.  
  162.             default:
  163.                 compiler_error( "Unknown kind of choice: ");
  164.             }
  165.         ENDFORTUP(ft2);
  166.         if (empty)
  167.             index -= 1;
  168.         else
  169.             bodies  = tup_with(bodies, (char *) body_node);
  170.     ENDFORTUP(ft1);
  171.  
  172.     result = tup_new(0);
  173.  
  174.     if (tup_size(triplets) != 0) { /* We may have a completely empty case */
  175.  
  176.         /* 2. sort the set of triples, giving a tuple */
  177.  
  178.         triplets = sort_case(triplets);
  179.  
  180.         /* 3. build the case table, filling gaps and merging adjacent cases */
  181.  
  182.         tup = (Tuple) tup_fromb(triplets);
  183.         a1 = (int) tup[1]; 
  184.         a2 = (int) tup[2]; 
  185.         a3 = (int) tup[3];
  186.         while(tup_size(triplets) != 0) {
  187.             tup = (Tuple) tup_fromb(triplets);
  188.             b1 = (int) tup[1]; 
  189.             b2 = (int) tup[2]; 
  190.             b3 = (int) tup[3];
  191.             if (a2 != b1-1) {  /* gap */
  192.                 tup = tup_new(2);
  193.                 tup[1] = (char *) a1;
  194.                 tup[2] = (char *) a3;
  195.                 result = tup_with(result, (char *) tup);
  196.                 tup = tup_new(2);
  197.                 tup[1] = (char *) (a2+1);
  198.                 tup[2] = (char *) 0;
  199.                 result = tup_with(result, (char *) tup);
  200.  
  201.                 a1 = b1; 
  202.                 a2 = b2; 
  203.                 a3 = b3;
  204.             }
  205.             else if (a3 == b3)  {  /* merge */
  206.                 a2 = b2; 
  207.                 a3 = b3;
  208.             }
  209.             else {
  210.                 tup = tup_new(2);
  211.                 tup[1] = (char *) a1;
  212.                 tup[2] = (char *) a3;
  213.                 result = tup_with(result, (char *) tup);
  214.                 a1 = b1; 
  215.                 a2 = b2; 
  216.                 a3 = b3;
  217.             }
  218.         }
  219.         tup  = tup_new(2);
  220.         tup[1] = (char *) a1;
  221.         tup[2] = (char *) a3;
  222.         result = tup_with(result, (char *) tup);
  223.         tup = tup_new(2);
  224.         if (a2 != MAX_INTEGER) {
  225.             tup[1] = (char *) a2+1;
  226.             tup[2] = (char *) 0;
  227.         }
  228.         else {
  229.             tup[1] = (char *) 0; /* does not really matter */
  230.             tup[2] = (char *) a3;/* merge with the preceeding */
  231.         }
  232.         result = tup_with(result, (char *) tup);
  233.     }
  234.  
  235.     tup = tup_new(3);
  236.     tup[1] = (char *) result;
  237.     tup[2] = (char *) bodies;
  238.     tup[3] = (char *) others_body;
  239.     return tup;
  240. }
  241.  
  242. static Tuple sort_case(Tuple tuple_to_sort)                        /*;sort_case*/
  243. {
  244.     /*
  245.      * Takes a set of case triples, and returns a tuple of those triple,
  246.      * sorted by ascending lower bounds. Quick sort algorithm.
  247.      * (sorry, this is not efficient, but was very easy to write)
  248.      */
  249.  
  250.     qsort((char *) &tuple_to_sort[1], tup_size(tuple_to_sort), sizeof (char *),
  251.       (int (*)(const void *, const void *))tcompar);
  252.     return tuple_to_sort;
  253. }
  254.  
  255. static int tcompar(Tuple *ptup1, Tuple *ptup2)                    /*;tcompar*/
  256. {
  257.     Tuple    tup1, tup2;
  258.     int        n1, n2;
  259.  
  260.     tup1 = *ptup1; 
  261.     tup2 = *ptup2;
  262.     /* called from sort_case to compare two elements in the case list */
  263.     n1 = (int) tup1[1];
  264.     n2 = (int) tup2[1];
  265.     if (n1 == n2) return 0;
  266.     else if (n1 < n2) return -1;
  267.     else return 1;
  268. }
  269.  
  270. void gen_case(Tuple case_table, Tuple bodies_arg, Node others_body,int mem_unit)
  271.                                                                 /*;gen_case*/
  272. {
  273.     /* Generates the code to select the right alternative and the bodies */
  274.     int        index, lower_bound, i, n;
  275.     Node    body_node;
  276.     Symbol    end_case, jumpsym;
  277.     Tuple    jump_table, tup;
  278.     Fortup    ft1;
  279.     Tuple    bodies;
  280.  
  281.     bodies = tup_copy(bodies_arg); /* copy needed since used in tup_fromb */
  282.     end_case = new_unique_name("end_case");
  283.     gen_k(I_CASE, mem_unit);
  284.     /* The SETL jump_table map is represented as a 'tuple map' in C, with
  285.      * procedures jump_table_get() and jump_table_put() (defined below) used
  286.      * to retrieve and insert values in this map.
  287.      */
  288.     jump_table = tup_new(0);
  289.     jump_table = jump_table_put(jump_table, 0, new_unique_name("case"));
  290.     gen_ks(I_CASE_TABLE, tup_size(case_table), jump_table_get(jump_table, 0)  );
  291.     FORTUP(tup = (Tuple), case_table, ft1);
  292.         lower_bound = (int) tup[1];
  293.         index = (int) tup[2];
  294.         jumpsym = jump_table_get(jump_table, index);
  295.         if (jumpsym == (Symbol)0) { /* if no entry yet, make new one */
  296.             jumpsym = new_unique_name("case");
  297.             jump_table = jump_table_put(jump_table, index, jumpsym);
  298.         }
  299.         gen_ks(I_CASE_TABLE, lower_bound, jumpsym);
  300.     ENDFORTUP(ft1);
  301.     index  = 0;
  302.     bodies = tup_exp(bodies, tup_size(bodies) + 1);
  303.     n = tup_size(bodies);
  304.     for (i = n; i > 1; i--) {
  305.         bodies[i] = bodies[i-1];
  306.     }
  307.     bodies[1] = (char *) others_body;
  308.     while (tup_size(bodies) != 0) {
  309.         body_node = (Node) tup_fromb(bodies);
  310.         gen_s(I_LABEL, jump_table_get(jump_table, index));
  311.         compile(body_node);
  312.         if (tup_size(bodies) != 0) { /* to avoid useless "jump $+1" */
  313.             gen_s(I_JUMP, end_case );
  314.         }
  315.         index += 1;
  316.     }
  317.     gen_s(I_LABEL, end_case);
  318.     tup_free(bodies);
  319. }
  320.  
  321. /* 5.6: block statement (compile_body) */
  322. void compile_body(Node decls_node, Node stmts_node, Node handler_node,
  323.   int is_block_statement)                                    /*;compile_body*/
  324. {
  325.     int        save_last_offset;
  326.     /* stack frame offset for local variables */
  327.     /* will overlap for blocks at the same nesting level */
  328.  
  329.     int        save_tasks_declared;
  330.     Symbol    start_handler, end_handler;
  331.  
  332.     CURRENT_LEVEL       += 1;
  333.     save_last_offset     = LAST_OFFSET;
  334.     save_tasks_declared  = TASKS_DECLARED;
  335.     TASKS_DECLARED       = FALSE;
  336.  
  337.     gen(I_ENTER_BLOCK);
  338.     compile(decls_node);
  339.     if (handler_node != OPT_NODE) {
  340.         start_handler = new_unique_name("handler");
  341.         gen_s(I_INSTALL_HANDLER, start_handler);
  342.     }
  343.     if (TASKS_DECLARED) {
  344.         gen(I_ACTIVATE);
  345.     }
  346.     compile(stmts_node);
  347.     if (handler_node != OPT_NODE) {
  348.         if (is_block_statement) {
  349.             /* use label allocated if return in accept else allocate
  350.              * a label for end of block (cf. comments in gen_accept)
  351.              */
  352.             if (symbol_accept_return != (Symbol)0) {
  353.                 end_handler = symbol_accept_return;
  354.             }
  355.             else {
  356.                 end_handler = new_unique_name("end_handler");
  357.             }
  358.             gen_s(I_JUMP, end_handler);
  359.             gen_s(I_LABEL, start_handler);
  360.             compile(handler_node);
  361.             gen_s(I_LABEL, end_handler);
  362.         }
  363.         else {
  364.             gen_s(I_LABEL, start_handler);
  365.             compile(handler_node);
  366.         }
  367.     }
  368.  
  369.     /*MAX_OFFSET  max= abs LAST_OFFSET;*/
  370.     MAX_OFFSET = offset_max(MAX_OFFSET, LAST_OFFSET);
  371.     LAST_OFFSET    = save_last_offset;
  372.     TASKS_DECLARED = save_tasks_declared;
  373.     CURRENT_LEVEL -= 1;
  374. }
  375.  
  376. void gen_condition(Node node, Symbol destination, int branch_cond)
  377.                                                             /*;gen_condition*/
  378. {
  379.     /* IMPORTANT WARNING: destination is where to go when expression is
  380.      *                    equal to branch_cond
  381.      */
  382.     /* These maps are realized in procedures immediately following.
  383.      *  const
  384.      * jump_false_code = {
  385.      *    ['=', I_JUMP_IF_FALSE],
  386.      *    ['!=', I_JUMP_IF_TRUE],
  387.      *    ['<', I_JUMP_IF_GREATER_OR_EQUAL],
  388.      *    ['>', I_JUMP_IF_LESS_OR_EQUAL],
  389.      *    ['<=', I_JUMP_IF_GREATER],
  390.      *    ['>=', I_JUMP_IF_LESS] },
  391.      * 
  392.      * jump_true_code = {
  393.      *    ['=', I_JUMP_IF_TRUE],
  394.      *    ['<', I_JUMP_IF_LESS],
  395.      *    ['>', I_JUMP_IF_GREATER],
  396.      *    ['<=', I_JUMP_IF_LESS_OR_EQUAL],
  397.      *    ['>=', I_JUMP_IF_GREATER_OR_EQUAL] };
  398.      */
  399.  
  400.     Tuple    tup;
  401.     Node    opnode, args, op1, op2;
  402.     Symbol    opcode, optype;
  403.  
  404. #ifdef TRACE
  405.     if (debug_flag)
  406.         gen_trace_node("GEN_CONDITION", node);
  407. #endif
  408.  
  409.     if (N_KIND(node) == as_op) {
  410.         opnode = N_AST1(node);
  411.         args = N_AST2(node);
  412.         opcode  = N_UNQ(opnode);
  413.         if (opcode == symbol_eq || opcode == symbol_ne || opcode == symbol_lt
  414.           || opcode == symbol_gt || opcode == symbol_le || opcode == symbol_ge){
  415.             tup = N_LIST(args);
  416.             op1 = (Node) tup[1];
  417.             op2     = (Node) tup[2];
  418.  
  419.             gen_value(op1);
  420.             gen_value(op2);
  421.             optype = get_type(op1);
  422.             if (is_simple_type(optype)) {
  423.                 if (is_float_type(optype))
  424.                     gen_k(I_FLOAT_COMPARE, kind_of(optype));
  425.                 else
  426.                     gen_k(I_COMPARE, kind_of(optype));
  427.             }
  428.             else {
  429.                 if (is_record_type(optype)) {
  430.                     gen_s(I_PUSH_EFFECTIVE_ADDRESS, optype);
  431.                 }
  432.                 if (is_array_type(optype) && 
  433.                     (opcode != symbol_eq) && (opcode != symbol_ne)) {
  434.                     gen(I_COMPARE_ARRAYS);
  435.                 }
  436.                 else {
  437.                     gen(I_COMPARE_STRUC);
  438.                 }
  439.             }
  440.         }
  441.         else {
  442.             gen_value(node);
  443.             opcode = symbol_eq;
  444.         }
  445.     }
  446.     else {
  447.         gen_value(node);
  448.         opcode = symbol_eq;
  449.     }
  450.  
  451.     if (branch_cond)
  452.         gen_s(jump_true_code(opcode), destination);
  453.     else
  454.         gen_s(jump_false_code(opcode), destination);
  455. }
  456.  
  457. static int jump_false_code(Symbol op)                    /*;jump_false_code*/
  458. {
  459.     if (op == symbol_eq) return I_JUMP_IF_FALSE;
  460.     else if (op == symbol_ne) return I_JUMP_IF_TRUE;
  461.     else if (op == symbol_lt) return I_JUMP_IF_GREATER_OR_EQUAL;
  462.     else if (op == symbol_gt) return I_JUMP_IF_LESS_OR_EQUAL;
  463.     else if (op == symbol_le) return I_JUMP_IF_GREATER;
  464.     else if (op == symbol_ge) return I_JUMP_IF_LESS;
  465.     else chaos("jump_false_code bad op");
  466.     return I_JUMP_IF_TRUE; /* return junk value */
  467. }
  468.  
  469. static int jump_true_code(Symbol op)                        /*;jump_true_code*/
  470. {
  471.     if (op == symbol_eq) return I_JUMP_IF_TRUE;
  472.     else if (op == symbol_ne) return I_JUMP_IF_FALSE;
  473.     else if (op == symbol_lt) return I_JUMP_IF_LESS;
  474.     else if (op == symbol_gt) return I_JUMP_IF_GREATER;
  475.     else if (op == symbol_le) return I_JUMP_IF_LESS_OR_EQUAL;
  476.     else if (op == symbol_ge) return I_JUMP_IF_GREATER_OR_EQUAL;
  477.     else chaos("jump_true_code");
  478.     return I_JUMP_IF_TRUE; /* return junk value for lint's sake */
  479. }
  480.  
  481. void gen_loop(Node node)                                        /*;gen_loop*/
  482. {
  483.     /* Generate loop stratements */
  484.     Node    id_node, iter_node, stmt_node, while_cond_node, var_node,
  485.       exp1_node, exp2_node;
  486.     Symbol    label_name, start_loop, start_while, end_while, var_name,
  487.       end_for, for_body, for_start, void_loop;
  488.     int        end_inst;
  489.     int        kind_var;
  490.     int         needs_check;
  491.     Const    val1, val2;
  492.  
  493.  
  494. #ifdef TRACE
  495.     if (debug_flag)
  496.         gen_trace_node("GEN_LOOP", node);
  497. #endif
  498.  
  499.     id_node = N_AST1(node);
  500.     iter_node = N_AST2(node);
  501.     stmt_node = N_AST3(node);
  502.  
  503.     if (id_node != OPT_NODE) {
  504.         label_name               = N_UNQ(id_node);
  505.         labelmap_put(label_name, LABEL_STATIC_DEPTH, (char *) CURRENT_LEVEL);
  506.         next_local_reference(label_name);
  507.         gen_s(I_SAVE_STACK_POINTER, label_name);
  508.     }
  509.  
  510.     if (iter_node == OPT_NODE) { /* simple loop */
  511.         start_loop = new_unique_name("loop");
  512.         gen_s(I_LABEL, start_loop);
  513.         compile(stmt_node);
  514.         gen_s(I_JUMP, start_loop );
  515.         if (id_node != OPT_NODE)
  516.             gen_s(I_LABEL, label_name);
  517.     }
  518.     else if (N_KIND(iter_node) == as_while) {     /* while loop */
  519.         while_cond_node = N_AST1(iter_node);
  520.         start_while  = new_unique_name("start_while");
  521.         end_while    = new_unique_name("end_while");
  522.         gen_sc(I_JUMP, end_while, "Test better at end of loop");
  523.         gen_s(I_LABEL, start_while);
  524.  
  525.         compile(stmt_node);
  526.         gen_s(I_LABEL, end_while);
  527.         gen_condition(while_cond_node, start_while, TRUE);
  528.  
  529.         if (id_node != OPT_NODE)
  530.             gen_s(I_LABEL, label_name);
  531.     }
  532.     else {                     /* for loop */
  533.         var_node = N_AST1(iter_node);
  534.         exp1_node = N_AST2(iter_node);
  535.         exp2_node = N_AST3(iter_node);
  536.         var_name = N_UNQ(var_node);
  537.         next_local_reference(var_name);
  538.         kind_var = kind_of(TYPE_OF(var_name));
  539.         val1     = get_ivalue(exp1_node);
  540.         val2     = get_ivalue(exp2_node);
  541.  
  542.         end_inst = ((N_KIND(iter_node) == as_for)) ?
  543.           I_END_FOR_LOOP : I_END_FORREV_LOOP;
  544.  
  545.         /* Static null range already checked by expander */
  546.  
  547.         if (val1->const_kind != CONST_OM && val2->const_kind != CONST_OM
  548.           && get_ivalue_int(exp1_node) == get_ivalue_int(exp2_node)) {
  549.             /* Loop executed only once, remove loop */
  550.             gen_value(exp1_node);
  551.             gen_k(I_CREATE_COPY, kind_var);
  552.             gen_s(I_UPDATE_AND_DISCARD, var_name);
  553.  
  554.             compile(stmt_node);
  555.  
  556.             if (id_node != OPT_NODE)
  557.                 gen_s(I_LABEL, label_name);
  558.             gen_s(I_PUSH_EFFECTIVE_ADDRESS, var_name);
  559.             gen(I_UNCREATE);
  560.         }
  561.         else {
  562.             needs_check = (val1->const_kind == CONST_OM
  563.               || val2->const_kind == CONST_OM );
  564.  
  565.             if (N_KIND(iter_node) == as_for) {
  566.                 gen_value(exp2_node);
  567.                 if (needs_check) {
  568.                     gen_k(I_DUPLICATE, kind_var);
  569.                 }
  570.                 gen_value(exp1_node);
  571.                 if (needs_check) {
  572.                     gen_k(I_DUPLICATE, kind_var);
  573.                 }
  574.             }
  575.             else {
  576.                 gen_value(exp1_node);
  577.                 if (needs_check) {
  578.                     gen_k(I_DUPLICATE, kind_var);
  579.                 }
  580.                 gen_value(exp2_node);
  581.                 if (needs_check) {
  582.                     gen_k(I_DUPLICATE, kind_var);
  583.                 }
  584.             }
  585.             for_start = new_unique_name("for_start");
  586.             for_body = new_unique_name("for_body");
  587.             end_for = new_unique_name("end_for");
  588.             if (needs_check) {
  589.                 void_loop = new_unique_name("void");
  590.                 gen_k(I_CREATE_COPY, kind_var);
  591.                 gen_s(I_UPDATE_AND_DISCARD, var_name);
  592.                 gen_k(I_COMPARE, kind_var);
  593.                 if (N_KIND(iter_node) == as_for) {
  594.                     gen_s(I_JUMP_IF_GREATER_OR_EQUAL, for_start);
  595.                 }
  596.                 else {
  597.                     gen_s(I_JUMP_IF_LESS_OR_EQUAL, for_start);
  598.                 }
  599.                 gen_ks(I_POP, kind_var, var_name);
  600.                 gen_s(I_JUMP, void_loop);
  601.                 gen_s(I_LABEL, for_start);
  602.                 gen_s(I_PUSH_EFFECTIVE_ADDRESS, var_name);
  603.             }
  604.             else
  605.             {  /* loop executed at least once, no need for check */
  606.                 gen_k(I_CREATE_COPY, kind_var);
  607.                 gen_s(I_UPDATE, var_name);
  608.             }
  609.             gen_s(I_LABEL, for_body);
  610.  
  611.             compile(stmt_node);
  612.  
  613.             gen_s(I_LABEL, end_for);
  614.             gen_ks(end_inst, kind_var, for_body );
  615.  
  616.             if (id_node != OPT_NODE) {
  617.                 gen_s(I_LABEL, label_name);
  618.             }
  619.  
  620.             if (needs_check) {
  621.                 gen_s(I_LABEL, void_loop);
  622.             }
  623.             gen_s(I_PUSH_EFFECTIVE_ADDRESS, var_name);
  624.             gen(I_UNCREATE);
  625.  
  626.         } /* static null loop */
  627.     }
  628. }
  629.  
  630. static Symbol jump_table_get(Tuple jtab, int ndx)        /*;jump_table_get()*/
  631. {
  632.     int        i, n;
  633.  
  634.     n = tup_size(jtab);
  635.     for (i = 1; i <= n; i += 2) {
  636.         if ((int) jtab[i] == ndx)
  637.             return (Symbol) jtab[i+1];
  638.     }
  639.     return (Symbol)0;
  640. }
  641.  
  642. static Tuple jump_table_put(Tuple jtab, int ndx, Symbol sym) /*;jump_table_put*/
  643. {
  644.     /* set value of jump_table jtab for int ndx to be sym. jtab is a map
  645.      * kept as tuple.
  646.      */
  647.  
  648.     int        i, n;
  649.  
  650.     n = tup_size(jtab);
  651.     for (i = 1; i <= n; i += 2) {
  652.         if ((int) jtab[i] == ndx) {
  653.             jtab[i+1] = (char *) sym;
  654.             return jtab;
  655.         }
  656.     }
  657.     /* here to add new entry */
  658.     jtab = tup_exp(jtab, n+2);
  659.     jtab[n+1] = (char *) ndx;
  660.     jtab[n+2] = (char *) sym;
  661.     return jtab;
  662. }
  663.